#include "bsp_gpio.h"
#include "amLog.h"

#define BSP_DEBUG_LOG_ENABLE
typedef struct 
{
    uint8_t irq_band;
    uint8_t reserved;
    uint16_t pin;
    GPIO_TypeDef *port;
    pbsp_gpio_irq_handler handler;
}BspGpioIrq_st;

#define BSP_GPIO_IRQ_MAX                16
#define BSP_GPIO_PORT_MAX               6
const GPIO_TypeDef *BSP_PORT_MAP[BSP_GPIO_PORT_MAX] = {GPIOA,GPIOB,GPIOC,GPIOD,GPIOE,GPIOF};
const uint16_t BSP_PIN_MAP[BSP_GPIO_IRQ_MAX] = {GPIO_PIN_0,GPIO_PIN_1,GPIO_PIN_2,GPIO_PIN_3,GPIO_PIN_4,GPIO_PIN_5,GPIO_PIN_6,
    GPIO_PIN_7,GPIO_PIN_8,GPIO_PIN_9,GPIO_PIN_10,GPIO_PIN_11,GPIO_PIN_12,GPIO_PIN_13,GPIO_PIN_14,GPIO_PIN_15};

static BspGpioIrq_st g_bsp_gpio_irq[BSP_GPIO_IRQ_MAX] = {0};

static int8_t bsp_gpio_port_get(GPIO_TypeDef * GPIO_Port)
{
    for(uint8_t i = 0;i < BSP_GPIO_PORT_MAX;i++)
    {
        if(GPIO_Port == BSP_PORT_MAP[i])
        {
            return i;
        }
    }
    return -1;
}

static int8_t bsp_gpio_pin_get(uint16_t pin)
{
    for(uint8_t i = 0;i < BSP_GPIO_IRQ_MAX;i++)
    {
        if(pin == BSP_PIN_MAP[i])
        {
            return i;
        }
    }
    return -1;
}

int8_t bsp_gpio_irq_set(void* port,uint16_t pin,uint8_t enable)
{
    GPIO_TypeDef *GPIO_Port = (GPIO_TypeDef *)port;
    if(bsp_gpio_port_get(GPIO_Port) < 0)
    {
        #ifdef BSP_DEBUG_LOG_ENABLE
        printf("BSP_GPIO %s port %d %ld\r\n",__func__,pin,(uint32_t)port);
        #endif
        return -1;
    }
    switch(pin)
    {
        case GPIO_PIN_0:
            if(enable)
                HAL_NVIC_EnableIRQ(EXTI0_IRQn);
            else
                HAL_NVIC_DisableIRQ(EXTI0_IRQn);
        break;
        case GPIO_PIN_1:
            if(enable)
                HAL_NVIC_EnableIRQ(EXTI1_IRQn);
            else
                HAL_NVIC_DisableIRQ(EXTI1_IRQn);
        break;
        case GPIO_PIN_2:
            if(enable)
                HAL_NVIC_EnableIRQ(EXTI2_IRQn);
            else
                HAL_NVIC_DisableIRQ(EXTI2_IRQn);
        break;
        case GPIO_PIN_3:
            if(enable)
                HAL_NVIC_EnableIRQ(EXTI3_IRQn);
            else
                HAL_NVIC_DisableIRQ(EXTI3_IRQn);
        break;
        case GPIO_PIN_4:
            if(enable)
                HAL_NVIC_EnableIRQ(EXTI4_IRQn);
            else
                HAL_NVIC_DisableIRQ(EXTI4_IRQn);
        break;
        case GPIO_PIN_5:
        case GPIO_PIN_6:
        case GPIO_PIN_7:
        case GPIO_PIN_8:
        case GPIO_PIN_9:
            if(enable)
                HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
            else
                HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
        break;
        case GPIO_PIN_10:
        case GPIO_PIN_11:
        case GPIO_PIN_12:
        case GPIO_PIN_13:
        case GPIO_PIN_14:
        case GPIO_PIN_15:
            if(enable)
                HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
            else
                HAL_NVIC_DisableIRQ(EXTI15_10_IRQn);
        break;
        default:
        #ifdef BSP_DEBUG_LOG_ENABLE
        printf("BSP_GPIO %s pin %d %ld\r\n",__func__,pin,(uint32_t)port);
        #endif
        return -2;
    }
    return 0;
}

int8_t bsp_gpio_irq_handler_register(void* port,uint16_t pin,pbsp_gpio_irq_handler handler)
{
    if(bsp_gpio_port_get(port) < 0)
    {
        #ifdef BSP_DEBUG_LOG_ENABLE
        printf("BSP_GPIO %s port %d %ld\r\n",__func__,pin,(uint32_t)port);
        #endif
        return -1;
    }
    int8_t pin_index = bsp_gpio_pin_get(pin);
    if(pin_index < 0)
    {
        #ifdef BSP_DEBUG_LOG_ENABLE
        printf("BSP_GPIO %s port %d %ld\r\n",__func__,pin,(uint32_t)port);
        #endif
        return -2;
    }
    else if(NULL == handler)
    {
        #ifdef BSP_DEBUG_LOG_ENABLE
        printf("BSP_GPIO %s handler null\r\n",__func__);
        #endif
        return -3;
    }
    g_bsp_gpio_irq[pin_index].handler = handler;
    g_bsp_gpio_irq[pin_index].port = (GPIO_TypeDef *)port;
    g_bsp_gpio_irq[pin_index].pin = pin;
    g_bsp_gpio_irq[pin_index].irq_band = 1;
    return 0;
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    int8_t pin_index = bsp_gpio_pin_get(GPIO_Pin);
    if(pin_index < 0)
    {
        return;
    }
    else
    {
        if(g_bsp_gpio_irq[pin_index].irq_band)
        {
            uint8_t value = HAL_GPIO_ReadPin(g_bsp_gpio_irq[pin_index].port,g_bsp_gpio_irq[pin_index].pin);
            g_bsp_gpio_irq[pin_index].handler(value);
        }
    }
}

